// src/monaco/dsql.ts
import type * as Monaco from 'monaco-editor'
import type {editor, Position} from 'monaco-editor'

// 常见 SQL 关键字/函数（可按需扩充）
const SQL_KEYWORDS: readonly string[] = [
    'select', 'insert', 'update', 'delete', 'into', 'values',
    'create', 'alter', 'drop', 'truncate', 'table', 'view', 'index', 'sequence', 'schema', 'database',
    'from', 'where', 'group', 'by', 'having', 'order', 'asc', 'desc', 'limit', 'offset', 'fetch', 'rows', 'only',
    'distinct', 'all', 'union', 'intersect', 'except', 'exists', 'between', 'like', 'in', 'is', 'null', 'not',
    'join', 'inner', 'left', 'right', 'full', 'outer', 'cross', 'on', 'using',
    'as', 'case', 'when', 'then', 'else', 'end', 'with', 'recursive', 'and', 'or',
]

const SQL_FUNCTIONS: readonly string[] = [
    'count', 'sum', 'avg', 'min', 'max',
    'coalesce', 'nullif', 'concat', 'substr', 'substring', 'length', 'upper', 'lower', 'trim',
    'cast', 'convert',
    'now', 'current_timestamp', 'date', 'time', 'strftime',
]

export function registerDSQL(monaco: typeof import('monaco-editor')) {
    const LANG_ID = 'dsql' as const
    if (monaco.languages.getLanguages().some(l => l.id === LANG_ID)) return

    // 1) 注册语言
    monaco.languages.register({id: LANG_ID})

    // 2) Monarch 语法高亮
    monaco.languages.setMonarchTokensProvider(LANG_ID, {
        ignoreCase: true,

        // 模板内置函数（函数调用高亮）
        builtinFunctions: [
            'length', 'trim', 'number', 'string',
            'ifnull', 'ifempty', 'if', 'typeof',
            'now', 'mill', 'id',
        ],
        // SQL 集合（供 cases 引用）
        sqlKeywords: SQL_KEYWORDS,
        sqlFunctions: SQL_FUNCTIONS,

        tokenizer: {
            root: [
                // SQL 注释
                [/--.*$/, 'comment'],
                [/\/\*/, {token: 'comment', next: '@comment'}],

                // 行首模板指令：必须是 "if: " 或 "for: "（冒号后恰好一个空格）
                [/^\s*(if|for): .*$/, {token: 'keyword'}],

                // 模板占位符
                [/#\{[^}]*\}/, 'macro'],     // #{...}
                [/\$\{[^}]*\}/, 'variable'], // ${...}

                // 字符串
                [/\'([^\'\\]|\\.)*\'/, 'string'],
                [/\"([^\"\\]|\\.)*\"/, 'string'],

                // 数字
                [/\b\d+(\.\d+)?\b/, 'number'],

                // 布尔/空
                [/\b(null|empty|true|false)\b/, 'constant'],

                // 括号/分隔
                [/[(),]/, 'delimiter'],

                // 多词/普通操作符
                [/\b(is\s+not|not\s+is|not\s+like|not\s+in|not\s+between)\b/, 'operator'],
                [/\b(and|or|is|like|in|between)\b/, 'operator'],
                [/==|!=|<=|>=|<|>/, 'operator'],

                // 函数调用（模板内置 + SQL 函数）
                [/\b[A-Za-z_]\w*(?=\s*\()/, {
                    cases: {
                        '@builtinFunctions': 'predefined',
                        '@sqlFunctions': 'predefined',
                        '@default': 'function',
                    }
                }],

                // 标识符（变量/列/表）——不再把裸 "if"/"for" 当关键字
                [/\b[A-Za-z_]\w*\b/, {
                    cases: {
                        '@sqlKeywords': 'keyword',
                        '@default': 'identifier',
                    }
                }],

                [/[;.:]/, 'delimiter'],
            ],

            comment: [
                [/[^\/*]+/, 'comment'],
                [/\*\//, {token: 'comment', next: '@root'}],
                [/[\/*]/, 'comment'],
            ],
        },
    } as Monaco.languages.IMonarchLanguage)

    // 3) 语言配置（只用 indentationRules 控制缩进）
    monaco.languages.setLanguageConfiguration(LANG_ID, {
        brackets: [
            ['{', '}'], ['[', ']'], ['(', ')'],
        ],
        autoClosingPairs: [
            { open: '"',  close: '"'  },
            { open: '\'', close: '\'' },
            { open: '(',  close: ')'  },
            { open: '[',  close: ']'  },
            { open: '{',  close: '}'  },
            { open: '${', close: '}'  },
            { open: '#{', close: '}'  },
        ],
        surroundingPairs: [
            { open: '"',  close: '"'  },
            { open: '\'', close: '\'' },
            { open: '(',  close: ')'  },
            { open: '[',  close: ']'  },
            { open: '{',  close: '}'  },
        ],

        // 只用缩进规则，要求“冒号后必须有一个空格”
        indentationRules: {
            increaseIndentPattern: /^\s*(if|for): .*$/i,
            decreaseIndentPattern: /^\s*end(if|for)\b/i,
        },

        // ✅ 不再提供 onEnterRules，避免覆盖缩进
        // onEnterRules: [],

        wordPattern: /(#\{[^}]+\}|\$\{[^}]+\}|[A-Za-z_]\w*|\d+(\.\d+)?)/g,
    })


    // 4) 智能补全（模板 + SQL）
    monaco.languages.registerCompletionItemProvider(LANG_ID, {
        // 去掉空格/Tab/引号触发，避免回车被“补全接受”拦截
        triggerCharacters: [':', '$', '#', '.', '('],
        provideCompletionItems(model: editor.ITextModel, position: Position): Monaco.languages.CompletionList {
            const word = model.getWordUntilPosition(position)
            const range = new monaco.Range(
                position.lineNumber,
                word ? word.startColumn : position.column,
                position.lineNumber,
                word ? word.endColumn : position.column
            )

            const suggestions: Monaco.languages.CompletionItem[] = []

            // 模板关键词（只是补全，不参与高亮）
            const tplKw: readonly string[] = ['if', 'for', 'and', 'or', 'is', 'not', 'like', 'in', 'between']
            suggestions.push(
                ...tplKw.map<Monaco.languages.CompletionItem>((k) => ({
                    label: k,
                    kind: monaco.languages.CompletionItemKind.Keyword,
                    insertText: k,
                    range,
                }))
            )

            // SQL 关键字
            suggestions.push(
                ...SQL_KEYWORDS.map<Monaco.languages.CompletionItem>((k) => ({
                    label: k,
                    kind: monaco.languages.CompletionItemKind.Keyword,
                    insertText: k.toUpperCase(),
                    range,
                }))
            )

            // 模板函数 + SQL 函数（Snippet）
            const tplFns: readonly string[] = [
                'length(${var})', 'trim(${str})', 'number(${strNumber})', 'string(${num})',
                'ifnull(${p1}, ${p2})', 'ifempty(${p1}, ${p2})', 'if(${cond}, ${p1}, ${p2})',
                'typeof(${param})', 'now()', 'mill()', 'id()',
            ]
            const sqlFnSnippets: readonly string[] = [
                'COUNT(${col})', 'SUM(${col})', 'AVG(${col})', 'MIN(${col})', 'MAX(${col})',
                'COALESCE(${a}, ${b})', 'CONCAT(${a}, ${b})', 'SUBSTR(${str}, ${from}, ${len})',
                'CAST(${expr} AS ${TYPE})',
            ]
            suggestions.push(
                ...tplFns.map<Monaco.languages.CompletionItem>((snippet) => ({
                    label: snippet,
                    kind: monaco.languages.CompletionItemKind.Function,
                    insertText: snippet,
                    insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
                    range,
                })),
                ...sqlFnSnippets.map<Monaco.languages.CompletionItem>((snippet) => ({
                    label: snippet,
                    kind: monaco.languages.CompletionItemKind.Function,
                    insertText: snippet,
                    insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
                    range,
                })),
            )

            // 片段
            suggestions.push(
                {
                    label: 'if-block',
                    kind: monaco.languages.CompletionItemKind.Snippet,
                    insertText: ['if: ${1:expr}', '\t${2:body}'].join('\n'),
                    insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
                    documentation: '条件块（基于缩进）',
                    range,
                },
                {
                    label: 'for-block',
                    kind: monaco.languages.CompletionItemKind.Snippet,
                    insertText: ['for: ${1:arr}', '\t${2:body}'].join('\n'),
                    insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
                    documentation: '循环块（基于缩进）',
                    range,
                },
                {
                    label: '${…}',
                    kind: monaco.languages.CompletionItemKind.Snippet,
                    insertText: '${${1:value}}',
                    insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
                    documentation: '模板占位符',
                    range,
                },
                {
                    label: '#{…}',
                    kind: monaco.languages.CompletionItemKind.Snippet,
                    insertText: '#{${1:value}}',
                    insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
                    documentation: '预编译占位符',
                    range,
                },
            )

            return {suggestions}
        },
    })
}
